package com.itelite.config;

import com.itelite.filter.JWTAuthenticationFilter;
import com.itelite.filter.JWTAuthorizationFilter;
import com.itelite.filter.VerificationCodeFilter;
import com.itelite.handler.MyLogoutSuccessHandler;
import com.itelite.security.MyAccessDeniedHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @author 沈洋 邮箱:1845973183@qq.com
 * @create 26-06-2021-19:37
 **/
@Slf4j
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    protected AuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    protected AuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private MyLogoutSuccessHandler logoutSuccessHandler;
    @Autowired
    private AccessDeniedHandler accessDeniedHandler;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置过滤器
        //将过滤器添加在用户名密码验证之前
        http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilter(new JWTAuthenticationFilter(authenticationManager()));
        http.addFilter(new JWTAuthorizationFilter(authenticationManager()));
        http.authorizeRequests()
                    //限制admin/api下面的接口只有具有ADMIN身份的用户才能访问
//                    .antMatchers("/admin/api/**").hasAnyRole("ADMIN")
                    //限制user/api下面的接口只有具有USER身份的用户才能访问
//                    .antMatchers("/user/api/**").hasAnyRole("USER","ADMIN")
//                    .antMatchers("/record/api/uploadTrainingRecord").hasAnyRole("USER","ADMIN")
                    //开放app/api下面所有的接口、验证码接口
                    .antMatchers("/captcha.jpg","/swagger-ui.html","/webjars/**","/v2/**","/swagger-resources/**"
                            ,"/record/**","/prize/**","/config/**","/cover/**","/config/api/carousel","/config/api/background","/teacher/api/teacher","/group/api/**"
                    ,"/druid/**","/user/api/auth/**").permitAll()
                    .anyRequest().authenticated()
                //关闭跨域
                .and()
                    .csrf().disable()
                    .formLogin()
                        //未认证的用户被拦截后处理的地方
                        .loginPage("/authentication/require")
                        //处理登陆请求的接口
                        .loginProcessingUrl("/login")
                        //登陆成功处理
                        .successHandler(authenticationSuccessHandler)
                        //登陆失败处理
                        .failureHandler(authenticationFailureHandler)
                        //登录请求放行
                        .permitAll()
                        //配置自定义无权限处理器
                        .and().exceptionHandling().accessDeniedHandler(accessDeniedHandler)
                .and()
                    .logout()//默认注销行为为logout
                        .logoutUrl("/logout")
                        .logoutSuccessHandler(logoutSuccessHandler)
                        .permitAll()
                .and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).maximumSessions(5);

        //                .and()
        //是否开启记住我
//                .rememberMe()
//                    .tokenRepository(persistentTokenRepository())
        //token保存时间
//                    .tokenValiditySeconds(3600)
//                    .userDetailsService(userDetailsService)

    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        //设置系统在启动时默认去创建一个管理记住我Token的数据库
//        tokenRepository.setCreateTableOnStartup(true);
        return tokenRepository;
    }

    @Bean
    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
    //自定义无权限访问的数据结构
    @Bean
    public AccessDeniedHandler getAccessDeniedHandler() {
        return new MyAccessDeniedHandler();
    }
    //随机盐被直接放到加密后的密码串中,验证时会自动取出里面的盐来进行匹配
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}
